iT邦幫忙

2023 iThome 鐵人賽

DAY 10
0

AJAX 相關

這邊寫了一個蠻常用的 hook 種類 useFetchUsers()

import axios from 'axios';
import { useState, useEffect } from 'react';

interface User {
  id: string;
  username: string;
}

function useFetchUsers() {
  const [users, setUsers] = useState<User[]>([]);

  const fetchUsers = async () => {
    const result = await axios.get<User[]('https://jsonplaceholder.typicode.com/users');
    setUsers(result.data);
  };

  useEffect(() => {
    fetchUsers();
  }, []);

  return users;
}

export default useFetchUsers;

那我們來寫他的測試吧,因為有 axios 跟 Promise 所以這次會用到

  • jest.spyOn :模擬 axios 會用到的
  • waitFor() : waitFor() 會回傳一個 Promise ,會等待 callback 的函式被拋出

由於這次 fetchUsers 只有是否有資料這兩個 case 要測試 ,按照 hook 的 return ,當 API 有問題時會回傳預設值空陣列

import axios from 'axios';
import { renderHook, waitFor } from '@testing-library/react';
import useFetchUsers from './index';

describe('測試 useFetchUsers', () => {
    it('fetches and returns users', async () => {
      
        const mock = jest.spyOn(axios, 'get');
        mock.mockResolvedValueOnce({
            data: [
                { id: '1', username: 'Dylan' },
                { id: '2', username: 'John' },
            ],
        });
        const hook = renderHook(() => useFetchUsers());
        await waitFor(() => {
            expect(hook.result.current).toEqual([
                { id: '1', username: 'Dylan' },
                { id: '2', username: 'John' },
            ]);
        });
    });

    it('if error return empty array ', async () => {
        const mock = jest.spyOn(axios, 'get');
        mock.mockRejectedValueOnce(new Error('error'));

        const hook = renderHook(() => useFetchUsers());
        await waitFor(() => {
            expect(hook.result.current).toEqual([]);
        });
    });

});
  測試 useFetchUsers
    ✓ fetches and returns users (72 ms)
    ✓ if error return empty array (44 ms)

Test Suites: 3 passed, 3 total
Tests:       8 passed, 8 total
Snapshots:   0 total

先利用 jest.spyOn 模擬 axios.get 要拿到的資料,後面再使用 waitFor() 等待Promise完成,有call api 的 hook 大多都可以這樣測試

waitFor 注意事項

waitFor 雖然好用,但有幾點需要注意

  1. 將空的回調函數傳遞給 waitFor
//不好的寫法

await waitFor(() => {})
expect(window.fetch).toHaveBeenCalledWith('foo')
expect(window.fetch).toHaveBeenCalledTimes(1)

// 好的寫法
await waitFor(() => expect(window.fetch).toHaveBeenCalledWith('foo'))
expect(window.fetch).toHaveBeenCalledTimes(1)
  1. waitFor 裡執行 side Effects
  
 //不好的寫法

await waitFor(() => {
      const hook = renderHook(() => useFetchUsers());
      expect(hook.result.current).toEqual([
          { id: '1', username: 'Dylan' },
          { id: '2', username: 'John' },
      ]);
});
     
//好的寫法

const hook = renderHook(() => useFetchUsers());
    await waitFor(() => {
        expect(hook.result.current).toEqual([
            { id: '1', username: 'Dylan' },
            { id: '2', username: 'John' },
        ]);
});

  1. 在一個 waitFor 內有多個斷言 (assertions)
//不好的寫法

await waitFor(() => {
  expect(window.fetch).toHaveBeenCalledWith('foo')
  expect(window.fetch).toHaveBeenCalledTimes(1)
})

// 好的寫法
await waitFor(() => expect(window.fetch).toHaveBeenCalledWith('foo'))
expect(window.fetch).toHaveBeenCalledTimes(1)

今天的測試就先到這,明天再一起看看更多測試吧!

waitFor() 注意事項參考這位大神的文章


上一篇
Day 9 - React Hooks 測試 part 1
下一篇
Day 11 - React Testing Library 元素選取
系列文
React Clean Code And Unit Tests - 利用測試寫出人類看得懂的React程式30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言